﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using NUnit.Framework;
using NUnit.Framework.SyntaxHelpers;
using QuickTest.Core.Events;
using QuickTest.Core.TestRunner;

namespace QuickTest.Tests.Core.TestRunner
{
    [TestFixture]
    public class NUnitTestRunnerTests
    {
        private ITestRunner testRunner;
        private ITestEvents testEvents;

        [SetUp]
        public void SetUp()
        {
            testRunner = new NUnitTestRunner();
            testEvents = new EventHub();
        }

        [Test]
        public void Can_Create_NUnit_Test_Runner()
        {
            Assert.That(testRunner, Is.InstanceOfType(typeof (NUnitTestRunner)), "Should create a NUnitTestRunner instance");
        }

        [Test]
        public void Can_Start_Test_Run()
        {
            bool runStarting = false;

            testEvents.RunStarted += (sender, e) => runStarting = true;
            testRunner.Run(GetTestPackage(), testEvents);

            Assert.That(runStarting, "Should raise RunStarted event");
        }

        [Test]
        public void Cannot_Pass_Null_TestPackage()
        {
            TestUtils.AssertThrows<ArgumentNullException>(() => testRunner.Run(null, testEvents),
                                                          "Should throw an ArgumentNullException if TestPackage is null");
        }

        [Test]
        public void Can_Get_Test_Count()
        {
            int testCount = 0;

            testEvents.RunStarted += (sender, e) => testCount = e.TestCount;
            testRunner.Run(GetTestPackage(), testEvents);

            Assert.That(testCount, Is.EqualTo(11), "Should get number of test cases in package");
        }

        [Test]
        public void Can_Get_Test_Result()
        {
            TestResult result = null;

            testEvents.TestFinished += (sender, e) => result = e.Result;
            testRunner.Run(GetTestPackage(), testEvents);

            Assert.That(result, Is.Not.Null, "Should get a test result");
        }

        [Test]
        public void Can_Get_Tests_Result_Count()
        {
            int resultCount = 0;

            testEvents.RunFinished += (sender, e) => resultCount = e.ResultCount;
            testRunner.Run(GetTestPackage(), testEvents);

            Assert.That(resultCount, Is.EqualTo(6), "Should get number of tests that were run");
        }

        [Test]
        public void Can_Get_Tests_Failed_Count()
        {
            int failedCount = 0;

            testEvents.RunFinished += (sender, e) => failedCount = e.FailureCount;
            testRunner.Run(GetTestPackage(), testEvents);

            Assert.That(failedCount, Is.EqualTo(0), "Should get number of tests that failed");
        }

        [Test]
        public void Can_Get_Tests_Success_Count()
        {
            int successCount = 6;

            testEvents.RunFinished += (sender, e) => successCount = e.SuccessCount;
            testRunner.Run(GetTestPackage(), testEvents);

            Assert.That(successCount, Is.EqualTo(6), "Should get number of tests that succeeded");
        }

        [Test]
        public void Can_Get_Tests_NotRun_Count()
        {
            int notRunCount = 0;

            testEvents.RunFinished += (sender, e) => notRunCount = e.NotRunCount;
            testRunner.Run(GetTestPackage(), testEvents);

            Assert.That(notRunCount, Is.EqualTo(5), "Should get number of tests that were not run");
        }

        [Test]
        public void Can_Complete_Test_Run()
        {
            bool runFinished = false;

            testEvents.RunFinished += (sender, e) => runFinished = true;
            testRunner.Run(GetTestPackage(), testEvents);

            Assert.That(runFinished, "Should raise RunFinished event");
        }

        #region Test Helpers

        public static readonly string BadFileName = "BAD_FILE_NAME";
        public static readonly string TestAssembly = "mock-assembly.dll";

        public static string GetTestAssemblyPath()
        {
            string rootPath = Path.GetDirectoryName(
                new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath);

            return String.Format(@"{0}\{1}", rootPath, TestAssembly);
        }

        public static ITestPackage GetTestPackage()
        {
            return new TestPackage(new List<string> {GetTestAssemblyPath()});
        }

        #endregion
    }
}